package com.mycompany.javabasics;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.Pattern;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager; // do not import java.util.logging.Level at the same time!
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App {

    public static void main(String[] args) {
        final Logger logger = LoggerFactory.getLogger(App.class);

        App controller = new App();
        try {
            // -----------------------
            controller.arrayBeispiel();
            controller.hashMapBeispiel();
            //controller.regExpressions();
            controller.loggingBeispiel();
            //controller.holeUmgebung();
            //controller.leseAusDatei();
            //controller.javascriptEngineBenutzen();
            controller.aufwaertsRundenAufVolle500();
            controller.pruefZiffernBeispiel();
            // -----------------------
        } catch (Exception ex) {
            /**
             * catching all exceptions like this is really dirt but I want to
             * keep the methods code exception clean - for educational reasons -
             * (your IDE will show you what exceptions are to be handled with)
             */
            logger.error("Nicht schön: Controller-Exception:", ex);
        }
    }

    /**
     * ########################## arrayBeispiel ################################
     */
    //public static void test(){};
    public void arrayBeispiel() {

        class EduDummy {

            public double skalarProdukt(double[] x, double[] y) {
                double result = 0.0;
                for (int i = 0; i < y.length; i++) {
                    result += x[i] * y[i];
                }
                return result;
            }

            public String vector2String(double[] x) {
                String vector2String = "(";

                for (int i = 0; i < x.length - 1; i++) {
                    vector2String = vector2String + x[i] + ",";
                }
                vector2String = vector2String + x[x.length - 1] + ")";
                return vector2String;
            }

            public String matrix2String(double[][] m) {
                String matrix2String = "";

                int numOfCols = m[0].length; // works as all rows have same number of col values
                int numOfRows = m.length; // works
                for (int i = 0; i < numOfRows; i++) {
                    for (int j = 0; j < numOfCols; j++) {
                        String tmp = String.format("%1$,8.2f", m[i][j]);
                        matrix2String = matrix2String + tmp;
                    }
                    matrix2String += System.getProperty("line.separator");
                }
                return matrix2String;
            }

        }

        double[] v1 = new double[3]; // length is 3, indices 0,1,2,3
        v1[0] = 1;
        v1[1] = 2;
        v1[2] = 4;

        double[] v2 = {2, 3, 4, 6}; // length is 4, indices 0,1,2,3
        double[] v3 = {1, 2, 3, 8};

        System.out.println("v1=" + (new EduDummy()).vector2String(v1));
        System.out.println("v2=" + (new EduDummy()).vector2String(v2));
        System.out.println("v3=" + (new EduDummy()).vector2String(v3));
        System.out.println("v1.length:" + v1.length + "v2.length:" + v2.length
                + " Arrays.equals(v1, v2):" + Arrays.equals(v1, v2));
        System.out.println("skalarProdukt v2*v3=" + (new EduDummy()).skalarProdukt(v2, v3));

        double[][] matrix = new double[3][4]; // defines a 3-row, 4-col matrix

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 4; j++) {
                matrix[i][j] = (i + 1) * 10 + j + 1;
            }
        }

        double[] rowOne = matrix[0]; // getting a row is easy ...
        System.out.println("rowOne=" + (new EduDummy()).vector2String(rowOne));

        System.out.println((new EduDummy()).matrix2String(matrix));

    }

    /**
     * ########################## hashMapBeispiel #############################
     */
    public void hashMapBeispiel() {

        // trying builder pattern here as well ... fluent, perhaps a little overkill
        Student.Builder studentBuilder = new Student.Builder();

        Student st1 = studentBuilder
                .name("Max")
                .geburtsdatum(new GregorianCalendar(2000, 6, 27))
                .matrikelNummer("0001")
                .build();

        Student st2 = studentBuilder
                .name("Hanna")
                .geburtsdatum(new GregorianCalendar(2005, 9, 27))
                .matrikelNummer("0002")
                .build();

        HashMap map = new HashMap();

        map.put(1, st1);
        map.put(2, st2);
        map.put(3, st2);

        Iterator<Integer> keySetIterator = map.keySet().iterator();

        while (keySetIterator.hasNext()) {
            Integer key = keySetIterator.next();
            System.out.println("key: " + key + " value: " + map.get(key).toString());
        }

        map.remove(
                3);
        System.out.println(
                "Is HashMap is empty: " + map.isEmpty());
        System.out.println(
                "Size of Map: " + map.size());
        System.out.println(
                "Does HashMap contains 2 as key: " + map.containsKey(2));
        System.out.println(
                "Does HashMap contains 3 as key: " + map.containsKey(3));
        System.out.println(
                "Does HashMap contains st1:" + map.containsValue(st1));
        System.out.println(
                "map.get(1):" + map.get(1));
    }

    /**
     * ########################## regExpressions ############################
     */
    public void regExpressions() {

        /**
         *
         * Example: email-Validation with regular expressions emailPattern =
         * [A-Za-z0-9_]+(?:[\.\-][ A-Za-z0-9_]+)*@[
         * A-Za-z0-9_]{1}[[A-Za-z0-9_].\-]*\.[A-Za-z]{2,} [A-Za-z0-9_] are the
         * "Word characters", i.e.letters, numbers and underscores, and can be
         * abbreviated with \w so this emailPattern may be rewritten as
         * emailPattern = [\w]+(?:[\.\-][\w]+)*@[\w]{1}[\w.\-]*\.[A-Za-z]{2,} As
         * a Java string one must \ with another escape character \. So the
         * final emailPattern is: emailPattern =
         * "[\\w]+(?:[\\.\\-][\\w]+)*@[\\w]{1}[\\w.\\-]*\\.[A-Za-z]{2,}"
         */
        String emailPattern = "[\\w]+(?:[\\.\\-][\\w]+)*@[\\w]{1}[\\w.\\-]*\\.[A-Za-z]{2,}";

        System.out.println("Pattern to match: " + emailPattern);

        String[] emailStringsToTest = {
            "test@test.de",
            "test@server-dest.de",
            "vorname.nachname@domain.com",
            "vorname.nachname@sub.domain.com",
            "vorname.nachname@s123-sub.123-domain.com",
            "test@@test.de", //zuviele @
            "test@test@test.de", //zuviele @
            "test.de", //unvollständig
            "test@test", //unvollständig
            "te st@test.de", //leerzeichen
            "test@test test.de", //leerzeichen
            "est@testtest.d e", //leerzeichen
            "gürke@test.ru" //umlaut
        };

        for (int i = 0; i < emailStringsToTest.length; i++) {
            String emailStringToTest = emailStringsToTest[i];
            System.out.println(String.format("%4d) ", i) + emailStringToTest
                    + " matches: " + Pattern.matches(emailPattern, emailStringToTest));
        }
    }

    /**
     * ########################## leseAusDatei ###############################
     */
    public void leseAusDatei() throws Exception {

        /**
         * aus Datei lesen mit InputStreamReader auf FileInputStream
         */
        String pathAndFilename = "C:\\800_fix\\400_JavaDev\\devProjects\\Javabasics\\src\\main\\java\\com\\mycompany\\javabasics\\testrules.drl";
        FileInputStream fileInputStream = null;
        fileInputStream = new FileInputStream(pathAndFilename);
        Reader inputStreamReader = new InputStreamReader(fileInputStream);

        //aus Datei lesen
        byte zeichen;
        String text = "";

        do {
            zeichen = (byte) inputStreamReader.read();
            System.out.print(zeichen + " ");
            text += (char) zeichen;
        } while (zeichen != -1);
        inputStreamReader.close();

        System.out.println();
        System.out.println(text);

        /**
         * aus Datei lesen mit BufferedReader auf FileReader
         */
        FileReader fileReader = null;
        String returnValue = null;
        fileReader = new FileReader(pathAndFilename);
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            returnValue += line + "\n";
        }
        fileReader.close();
        System.out.println(returnValue);
    }

    /**
     * ########################## holeUmgebung ##############################
     */
    public void holeUmgebung() {

        /**
         * Umgebung mit System.getenv abfragen
         */
        System.out.println("System.getenv(\"PATH\") = " + System.getenv("PATH"));
    }

    /**
     * ########################## loggingBeispiel #############################
     */
    public void loggingBeispiel() {

        /**
         * loggingBeispiel - Achtung App uses slf4j as logging API over jul
         */
        final Logger logger = LoggerFactory.getLogger(App.class);

        logger.trace("Hello World!");
        logger.debug("How are you today?");
        logger.info("I am fine.");
        logger.warn("I love programming.");
        logger.error("I am programming.");
        //LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        //lc.setLoggingLevel(ch.qos.logback.classic.Level.DEBUG);
        logger.info("info msg");
        logger.debug("debug msg");

        String jft_id = "112";
        String jft_symbol = "square";
        logger.debug("Processing trade with id: {} and symbol : {} ", jft_id, jft_symbol);

    }

    /**
     * ########################## javascriptEngineBenutzen ####################
     */
    public void javascriptEngineBenutzen() throws Exception {

        /**
         * javascriptEngineBenutzen
         */
        ScriptEngine e = new ScriptEngineManager().getEngineByName("js");
        e.put("x", "hanna");
        e.eval("print('Hello ' + x + '!')");
        e.put("x", 3);
        String myFunction = "Math.sin(Math.cos(x))";
        double dw2;
        dw2 = ((Number) e.eval(myFunction)).doubleValue();
        System.out.println("ScriptEngine sagt: dw2 = " + myFunction + " = " + dw2);

    }

    public void aufwaertsRundenAufVolle500() {

        int gerundet;

        for (int i = 50; i < 6000; i = i + 50) {
            gerundet = auf500Aufgerundet(i);
            System.out.println(i + " --> " + gerundet);
        }
    }

    private int auf500Aufgerundet(int nichtGerundet) {
        int gerundet = 500 * (1 + (int) ((nichtGerundet - 1) / 500));
        return gerundet;
    }

    private Integer berechnePruefziffer(String wert) {
        /*
        berechnet die Prüfziffer modulo 11 für Zahlen und Zeichenketten
        beliebiger Länge
        */

        int MODULO_6 = 6;
        int MODULO_10 = 10;
        int MODULO_11 = 11;

        int n = 0;
        int len = wert.length();

        for (int i = 0;
                i < len;
                i++) {
            n += Character.getNumericValue(wert.charAt(len - 1 - i)) * (2 + (i % MODULO_6));
        }
        int pz = (MODULO_11 - (n % MODULO_11)) % MODULO_10;

        return pz;
    }
    
    private void pruefZiffernBeispiel(){
        
        
        System.out.println("pruefziffer von '1234567': " + berechnePruefziffer("1234567"));
        System.out.println("pruefziffer von '123 4567': " + berechnePruefziffer("123 4567"));
        System.out.println("pruefziffer von '1111111': " + berechnePruefziffer("1111111"));
        System.out.println("pruefziffer von 'Johanna':" + berechnePruefziffer("Johanna"));
        System.out.println("pruefziffer von 'Johanna und Max':" + berechnePruefziffer("Johanna und Max"));
        
    }

}
